/*
Copyright (c) [2019年5月1日] [吴超]
[MBT_Studio] is licensed under Mulan PSL v2.
You can use this software according to the terms and conditions of the Mulan PSL v2.
You may obtain a copy of Mulan PSL v2 at:
		 http://license.coscl.org.cn/MulanPSL2
THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
See the Mulan PSL v2 for more details.
*/
#include "stdafx.h"
#include "粒子发射器.h"

#include "面/几何模型生成.h"

#include <材质/S_Material.h>

#include "../插座/通用插座.h"
#include "../插座/C_粒子插座.h"
#include "../插座/C_数值插座.h"
#include "../插座/list/list数值插座.h"
#include "../插座/list/list物理物体插座.h"

#include "Context/当前默认操作数据.h"

#include "Range.h"
#include <随机数.h>


C_粒子节点::C_粒子节点(S_设备环境& ctx) : C_节点基类("粒子节点") {
	m_Name = L"粒子节点";

	C_插座基类* socket;
	DEF_创建UI32_1D插座_I(L"粒子数量");
	DEF_创建物理引擎插座_I(L"物理引擎");
	DEF_创建F32插座_v1_I(L"寿命");
	DEF_创建F32插座_v1_I(L"大小");
	//DEF_创建UI32插座_I(L"粒子数量");
	
	DEF_创建粒子插座_O(L"粒子系统");

	/*auto* psys = DEF_粒子插座Value(f_get输出插座(1), 0);
	uint32 初始粒子数量 = 20000;
	psys->m_Psy = f_create粒子系统(初始粒子数量, ctx);
	psys->m_粒子点 = f_ob_创建物体(E_物体类型::t_网格, 0, ctx);
	S_Mesh* mesh = f_ob_fromMesh(psys->m_粒子点);
	S_单色点材质* 材质 = new S_单色点材质(ctx);
	f_ob_set材质(psys->m_粒子点, 材质);
	psys->m_Psy->m_Count = 初始粒子数量;
	std::vector<S_VC> 顶点数据(psys->m_Psy->m_Count);
	f_surface_fill顶点数据(mesh, 顶点数据);
	*DEF_UI32插座数据(f_get输入插座(1), 0) = psys->m_Psy->m_Count;*/
	//m_粒子点 = psys->m_粒子点;
}

bool C_粒子节点::f_update() {
	S_Physics* phy = nullptr;

	if (f_get输入插座(1)->f_isLink()) {
		phy = DEF_物理引擎插座数据(f_get输入插座(2));

		
	}
	
	auto& 粒子数量 = *DEF_UI32插座_1D数据(f_get输入插座(1));
	
	auto* psys = DEF_粒子插座Value(f_get输出插座(1), 0);

	if (phy) {
		switch (phy->m_IdType)
		{
		case E_物理引擎::E_物理引擎_FleX: {
			psys->m_粒子->m_Loc.clear();
			psys->m_粒子->m_Size.clear();
			
			//for (auto e : 粒子数量) {
			//	psys->m_粒子->m_Size.reserve(e);
			//	phy->f_get粒子坐标(e, psys->m_粒子->m_Loc);
			//	phy->f_get粒子大小(e, psys->m_粒子->m_Size);
			//}
			break;
		}
		default:
			break;
		}
	}

	

	/*auto 粒子数量 = *DEF_UI32插座数据(f_get输入插座(1), 0);

	auto* psys = DEF_粒子插座Value(f_get输出插座(1), 0);
	if (f_ob_get顶点数量(psys->m_粒子点) != 粒子数量) {
		//f_ob_set实例数量(psys->m_粒子点, 粒子数量);
		f_ob_重置顶点数量(psys->m_粒子点, 粒子数量);
	}

	uint16 loc = f_get输入插座连接到输出插座数据位置(2);
	if (loc != 0xffff) {
		psys->m_Psy->m_绘制类型 = E_粒子绘制类型::E_粒子物体_物理后端映射;
		psys->m_Psy->m_物理引擎 = (S_结构对象指针) & (f_NodeCtx_get默认场景()->m_Physics);

		auto& bodys = *DEF_物理体插座_1D数据(f_get输入插座(2), 0);
		f_Phy_设置粒子数量((S_物理解算器*)(psys->m_Psy->m_物理引擎), bodys[loc], 粒子数量);
		f_particle_设置物理属性(psys->m_Psy, bodys[loc]);

	}*/
	return false;
}


C_节点基类* f_node_加载粒子节点(S_设备环境& ctx, FILE* f) {
	C_粒子节点* node = new C_粒子节点(ctx);

	return node;
}

void f_node_保存粒子节点(C_节点基类* n, FILE* f)
{
	C_粒子节点* node = dynamic_cast<C_粒子节点*>(n);

}









C_点粒子发射节点::C_点粒子发射节点(S_设备环境& ctx) : C_节点基类("点粒子发射节点") {
	m_Name = L"点粒子发射节点";


	C_插座基类* socket;

	DEF_创建粒子插座_I(L"粒子系统");
	DEF_创建UI32插座_I(L"粒子数量");
	DEF_创建F32插座_v1_I(L"发射速度");

	DEF_创建粒子插座_O(L"粒子系统");


	m_发射体物体 = f_ob_创建物体(E_物体类型::t_网格, 0, ctx);
	S_Mesh* mesh = f_ob_fromMesh(m_发射体物体);
	S_单色线框材质*	材质 = new S_单色线框材质(ctx);

	std::vector<vec3> 顶点数据;

	f_graph_计算圆坐标v3({0,0,0}, 1.0f, 顶点数据.size(), 顶点数据.data());
	


	f_surface_fill顶点数据(mesh, 顶点数据);
	f_ob_set材质(m_发射体物体, 材质);

}

bool C_点粒子发射节点::f_update() {
	return false;
}











C_面粒子发射节点::C_面粒子发射节点(S_设备环境& ctx) : C_节点基类("面粒子发射节点") {
	m_Name = L"面粒子发射节点";
	m_更新方式 = E_节点更新方式::e_节点更新_逐帧;


	C_插座基类* socket;
	DEF_创建粒子插座_I(L"粒子系统");
	DEF_创建UI32插座_I(L"发射数量");
	DEF_创建F32插座_v1_I(L"发射速度");
	DEF_创建F32插座_v1_I(L"发射半径");

	DEF_创建粒子插座_O(L"粒子系统");
	



	uint32 init发射数量 = 30;
	float32 init发射速度 = 0.03;
	float32 init发射半径 = 1;
	f_get输入插座(2)->f_setData(&init发射数量);
	f_get输入插座(3)->f_setData(&init发射速度);
	f_get输入插座(4)->f_setData(&init发射半径);


	m_发射体物体 = f_ob_创建物体(E_物体类型::t_网格, 0, ctx);
	S_Mesh* mesh = f_ob_fromMesh(m_发射体物体);
	S_单色线框材质* 材质 = new S_单色线框材质(ctx);

	std::vector<vec3> 顶点数据(64);

	f_graph_计算圆坐标v3({ 0,0,0 }, 1.0f, 64, 顶点数据.data());
	顶点数据.push_back(顶点数据.front());


	顶点数据.push_back({ 0,0,0 });
	顶点数据.push_back({ 0,1.5f,0 });

	顶点数据.push_back({ 0,1.5f,0 });
	顶点数据.push_back({ 0.4f, 1.0f, 0.0f });

	顶点数据.push_back({ 0,1.5f,0 });
	顶点数据.push_back({ -0.4f, 1.0f, 0.0f });

	顶点数据.push_back({ 0,1.5f,0 });
	顶点数据.push_back({ 0.0f, 1.0f, 0.4f });

	顶点数据.push_back({ 0,1.5f,0 });
	顶点数据.push_back({ 0.0f, 1.0f, -0.4f });


	f_surface_fill顶点数据(mesh, 顶点数据, E_顶点组合标志::e_坐标);
	f_ob_set材质(m_发射体物体, 材质);
	f_ob_set线宽(m_发射体物体, 2.2);
}

bool C_面粒子发射节点::f_update() {
	auto& psys = *DEF_粒子插座Value(f_get输入插座(1), 0);
	auto 发射数量 = DEF_UI32插座数据(f_get输入插座(2), 0);
	auto 发射速度 = DEF_F32插座数据(f_get输入插座(3));
	auto 发射半径 = DEF_F32插座数据(f_get输入插座(4));
		

	

	if (psys.m_Psy) {
		auto* mesh = f_ob_fromMesh(psys.m_粒子点);


		
		bool 物理配置 = f_particle_map物理引擎(psys.m_Psy);
		if(!物理配置) return false;
		vec3* 位置 = (vec3*)(psys.m_Psy->m_Loc);
		vec3* 速度 = (vec3*)(psys.m_Psy->m_Vel);


		std::vector<S_RGBA8UI> col(psys.m_Psy->m_Count);
		for (uint32 i = 0; i < psys.m_Psy->m_Count; ++i) {
			col[i] = { 255,255,100,255 };
		}

		//物理数据读回
		mesh->f_重置顶点数量(psys.m_Psy->m_Count);
		mesh->f_fill顶点(位置, psys.m_Psy->m_Count);
		//auto mv = mesh->f_map顶点();
		//if (psys.m_Psy->m_物理属性) {
			//f_Phy_拷贝粒子坐标((S_物理解算器*)psys.m_Psy->m_物理引擎, psys.m_Psy->m_物理属性, (vec3*)mv.point);
		//}
		//mesh->f_unmap顶点();
		//f_填充顶点数据(mesh, vec, E_顶点组合标志::e_坐标_颜色);
		f_填充颜色数据(mesh, col);
		//vec3* 位置 = f_buf_map板载缓存<vec3>(psys.m_Psy->m_Loc);
		//vec3* 速度 = f_buf_map板载缓存<vec3>(psys.m_Psy->m_Vel);
		
		//std::vector<vec3> vec(psys.m_Psy->m_Count);
		//
		//static int32 随机种子 = 1;
		//++随机种子;
		//f_随机向量(vec, uint64(psys.m_Psy->m_Count), { -1,1 }, 随机种子);
		float32 发射面积 = M_PI * 发射半径 * 发射半径;

		float32 发射粒子间隔 = 发射面积 /= 发射数量;
		int32 步数 = 发射半径*2 / 发射粒子间隔;
		float32 步进 = 180.0 / 步数;
		
		float32 Xoffset = -发射半径 + 发射粒子间隔*0.5;
		for (uint16 x = 0; x < 步数; ++x) {
			float32 s = fabs(sin(float32(M_角度转弧度(步进 * x))));
			//uint32 Z发射步数 = DEF_Max(1, s * 步数);
			uint32 Z发射步数 = uint32(s * 步数 + 0.5);
			float32 Zoffset = (发射粒子间隔 * 步数 - (Z发射步数 * 发射粒子间隔)) * 0.5f - 发射半径 + 发射粒子间隔*0.5f;
			for (uint16 z = 0; z < Z发射步数; ++z) {
				vec_fill(&位置[psys.m_Psy->m_发射粒子ID偏移], { x * 发射粒子间隔 + Xoffset, 0, z * 发射粒子间隔 + Zoffset });
				
				速度[psys.m_Psy->m_发射粒子ID偏移] = { 0, 发射速度, 0 };

				++psys.m_Psy->m_发射粒子ID偏移;
				if (psys.m_Psy->m_发射粒子ID偏移 >= psys.m_Psy->m_Count) {
					psys.m_Psy->m_发射粒子ID偏移 = 0;
				}
				
			}
		}


		//================== 物理计算 ===================

		//To_结束发射:
		//for (uint32 i = 0; i < psys.m_Psy->m_Count; ++i) {
			//速度[i] = {0.00f, 0.01f, 0.00f};
		//	vec_add(&速度[i], vec3{ 0.00f, 0.005f, 0.00f });
		//	vec_add(&位置[i], 速度[i]);
			//vec_fill(&vec[i], 位置[i]);
			//col[i] = {255,255,100,255};
		//}
		//f_buf_unmap板载缓存(psys.m_Psy->m_Loc);
		//f_buf_unmap板载缓存(psys.m_Psy->m_Vel);

	}

	
	f_get输出插座(1)->f_setData(&psys);

	return false;
}

C_节点基类* f_node_加载手动面粒子发射节点(S_设备环境& ctx, FILE* f) {
	C_面粒子发射节点* node = new C_面粒子发射节点(ctx);
	return node;
}


